///**
// * 
// */
//package org.swing.utility.sytem.jar;
//
//import java.io.IOException;
//import java.lang.reflect.AccessibleObject;
//import java.lang.reflect.Constructor;
//import java.lang.reflect.Field;
//import java.lang.reflect.InvocationHandler;
//import java.lang.reflect.Method;
//import java.lang.reflect.Proxy;
//import java.nio.file.Files;
//import java.nio.file.Path;
//import java.util.ArrayList;
//import java.util.List;
//import java.util.Map;
//import java.util.Properties;
//import java.util.jar.Manifest;
//
//import org.swing.utility.system.conts.Attribute;
//import org.swing.utility.system.imp.Capsule;
//
//import static org.swing.utility.system.exception.Exceptions.rethrow;
//
///**
// * @author lqnhu
// *
// */
//public final class CapsuleLauncher {
//	private static final String CAPSULE_CLASS_NAME = "Capsule";
//	private static final String OPT_JMX_REMOTE = "com.sun.management.jmxremote";
//	private static final String ATTR_MAIN_CLASS = "Main-Class";
//	private static final String PROP_MODE = "capsule.mode";
//	private final Path jarFile;
//	private final Class capsuleClass;
//	private Properties properties;
//
//	public CapsuleLauncher(Path jarFile) throws IOException {
//		this.jarFile = jarFile;
//		this.capsuleClass = loadCapsuleClass(jarFile);
//		setProperties(null);
//	}
//
//	/**
//	 * Sets the Java homes that will be used by the capsules created by
//	 * {@code newCapsule}.
//	 *
//	 * @param javaHomes
//	 *            a map from Java version strings to their respective JVM
//	 *            installation paths
//	 * @return {@code this}
//	 */
//	public CapsuleLauncher setJavaHomes(Map<String, List<Path>> javaHomes) {
//		final Field homes = getCapsuleField("JAVA_HOMES");
//		if (homes != null)
//			set(null, homes, javaHomes);
//		return this;
//	}
//
//	/**
//	 * Sets the properties for the capsules created by {@code newCapsule}
//	 *
//	 * @param properties
//	 *            the properties
//	 * @return {@code this}
//	 */
//	public CapsuleLauncher setProperties(Properties properties) {
//		this.properties = properties != null ? properties : new Properties(
//				System.getProperties());
//		set(null, getCapsuleField("PROPERTIES"), this.properties);
//		return this;
//	}
//
//	/**
//	 * Sets a property for the capsules created by {@code newCapsule}
//	 *
//	 * @param property
//	 *            the name of the property
//	 * @param value
//	 *            the property's value
//	 * @return {@code this}
//	 */
//	public CapsuleLauncher setProperty(String property, String value) {
//		if (value != null)
//			properties.setProperty(property, value);
//		else
//			properties.remove(property);
//		return this;
//	}
//
//	/**
//	 * Sets the location of the cache directory for the capsules created by
//	 * {@code newCapsule}
//	 *
//	 * @param dir
//	 *            the cache directory
//	 * @return {@code this}
//	 */
//	public CapsuleLauncher setCacheDir(Path dir) {
//		set(null, getCapsuleField("CACHE_DIR"), dir);
//		return this;
//	}
//
//	/**
//	 * Creates a new capsule.
//	 */
//	public Capsule newCapsule() {
//		return newCapsule(null, null);
//	}
//
//	/**
//	 * Creates a new capsule
//	 *
//	 * @param mode
//	 *            the capsule mode
//	 * @return the capsule.
//	 */
//	public Capsule newCapsule(String mode) {
//		return newCapsule(mode, null);
//	}
//
//	/**
//	 * Creates a new capsule
//	 *
//	 * @param wrappedJar
//	 *            a path to a capsule JAR that will be launched (wrapped) by the
//	 *            empty capsule in {@code jarFile} or {@code null} if no wrapped
//	 *            capsule is wanted
//	 * @return the capsule.
//	 */
//	public Capsule newCapsule(Path wrappedJar) {
//		return newCapsule(null, wrappedJar);
//	}
//
//	/**
//	 * Creates a new capsule
//	 *
//	 * @param mode
//	 *            the capsule mode, or {@code null} for the default mode
//	 * @param wrappedJar
//	 *            a path to a capsule JAR that will be launched (wrapped) by the
//	 *            empty capsule in {@code jarFile} or {@code null} if no wrapped
//	 *            capsule is wanted
//	 * @return the capsule.
//	 */
//	public Capsule newCapsule(String mode, Path wrappedJar) {
//		final String oldMode = properties.getProperty(PROP_MODE);
//		try {
//			setProperty(PROP_MODE, mode);
//			final Constructor<?> ctor = accessible(capsuleClass
//					.getDeclaredConstructor(Path.class));
//			final Object capsule = ctor.newInstance(jarFile);
//			if (wrappedJar != null) {
//				final Method setTarget = accessible(capsuleClass
//						.getDeclaredMethod("setTarget", Path.class));
//				setTarget.invoke(capsule, wrappedJar);
//			}
//			return wrap(capsule);
//		} catch (ReflectiveOperationException e) {
//			throw new RuntimeException("Could not create capsule instance.", e);
//		} finally {
//			setProperty(PROP_MODE, oldMode);
//		}
//	}
//
//	private static Class<?> loadCapsuleClass(Path jarFile) throws IOException {
//		final Manifest mf;
//		try (JarInputStream jis = new JarInputStream(Files.newInputStream(jarFile))) {
//			mf = jis.getManifest();
//		}
//		final ClassLoader cl = new JarClassLoader(jarFile, true);
//		final Class<?> clazz = loadCapsuleClass(mf, cl);
//		if (clazz == null)
//			throw new RuntimeException(jarFile
//					+ " does not appear to be a valid capsule.");
//		return clazz;
//	}
//
//	private static Class<?> loadCapsuleClass(Manifest mf, ClassLoader cl) {
//		final String mainClass = mf.getMainAttributes() != null ? mf
//				.getMainAttributes().getValue(ATTR_MAIN_CLASS) : null;
//		if (mainClass == null)
//			return null;
//		try {
//			Class<?> clazz = cl.loadClass(mainClass);
//			if (!isCapsuleClass(clazz))
//				clazz = null;
//			return clazz;
//		} catch (ClassNotFoundException e) {
//			return null;
//		}
//	}
//
//	private static boolean isCapsuleClass(Class<?> clazz) {
//		if (clazz == null)
//			return false;
//		return getActualCapsuleClass(clazz) != null;
//	}
//
//	private static Capsule wrap(Object capsule) {
//		return (Capsule) Proxy.newProxyInstance(
//				CapsuleLauncher.class.getClassLoader(),
//				new Class<?>[] { Capsule.class }, new CapsuleAccess(capsule));
//	}
//
//	private static class CapsuleAccess implements InvocationHandler {
//		private final Object capsule;
//		private final Class<?> clazz;
//
//		public CapsuleAccess(Object capsule) {
//			this.capsule = capsule;
//			this.clazz = capsule.getClass();
//		}
//
//		public Object invoke(Object proxy, Method method, Object[] args)
//				throws Throwable {
//			if (method.getDeclaringClass().equals(Object.class)
//					&& method.getName().equals("equals")) {
//				final Object other = args[0];
//				if (other == this)
//					return true;
//				if (!(other instanceof CapsuleAccess))
//					return false;
//				return call(method, args);
//			}
//			try {
//				return call(method, args);
//			} catch (NoSuchMethodException e) {
//				switch (method.getName()) {
//				case "getVersion":
//					return get("VERSION");
//				case "getProperties":
//					return get("PROPERTIES");
//				case "getAttribute":
//					return getMethod(clazz, "getAttribute", Map.Entry.class)
//							.invoke(capsule, ((Attribute) args[0]).toEntry());
//				case "hasAttribute":
//					return getMethod(clazz, "hasAttribute", Map.Entry.class)
//							.invoke(capsule, ((Attribute) args[0]).toEntry());
//				default:
//					throw new UnsupportedOperationException("Capsule " + clazz
//							+ " does not support this operation");
//				}
//			}
//		}
//
//		private Object call(Method method, Object[] args)
//				throws NoSuchMethodException {
//			final Method m = getMethod(clazz, method.getName(),
//					method.getParameterTypes());
//			if (m == null)
//				throw new NoSuchMethodException();
//			return CapsuleLauncher.invoke(capsule, m, args);
//		}
//
//		private Object get(String field) {
//			final Field f = getField(clazz, field);
//			if (f == null)
//				throw new UnsupportedOperationException("Capsule " + clazz
//						+ " does not contain the field " + field);
//			return CapsuleLauncher.get(capsule, f);
//		}
//	}
//
//	/**
//	 * Returns all known Java installations
//	 *
//	 * @return a map from the version strings to their respective paths of the
//	 *         Java installations.
//	 */
//	@SuppressWarnings("unchecked")
//	public static Map<String, List<Path>> findJavaHomes() {
//		try {
//			return (Map<String, List<Path>>) accessible(
//					Class.forName(CAPSULE_CLASS_NAME).getDeclaredMethod(
//							"getJavaHomes")).invoke(null);
//		} catch (ReflectiveOperationException e) {
//			throw new AssertionError(e);
//		}
//	}
//
//	/**
//	 * Adds an option to the JVM arguments to enable JMX connection
//	 *
//	 * @param jvmArgs
//	 *            the JVM args
//	 * @return a new list of JVM args
//	 */
//	public static List<String> enableJMX(List<String> jvmArgs) {
//		final String arg = "-D" + OPT_JMX_REMOTE;
//		if (jvmArgs.contains(arg))
//			return jvmArgs;
//		final List<String> cmdLine2 = new ArrayList<String>(jvmArgs);
//		cmdLine2.add(arg);
//		return cmdLine2;
//	}
//
//	private Field getCapsuleField(String name) {
//		return getField(getActualCapsuleClass(capsuleClass), name);
//	}
//
//	// <editor-fold defaultstate="collapsed" desc="Reflection">
//	// ///////// Reflection ///////////////////////////////////
//	private static Method getMethod(Class<?> clazz, String name,
//			Class<?>... paramTypes) {
//		try {
//			return clazz.getMethod(name, paramTypes);
//		} catch (NoSuchMethodException e) {
//			return getMethod0(clazz, name, paramTypes);
//		}
//	}
//
//	private static Method getMethod0(Class<?> clazz, String name,
//			Class<?>... paramTypes) {
//		try {
//			return accessible(clazz.getDeclaredMethod(name, paramTypes));
//		} catch (NoSuchMethodException e) {
//			return clazz.getSuperclass() != null ? getMethod0(
//					clazz.getSuperclass(), name, paramTypes) : null;
//		}
//	}
//
//	private static Field getField(Class<?> clazz, String name) {
//		try {
//			return accessible(clazz.getDeclaredField(name));
//		} catch (NoSuchFieldException e) {
//			return clazz.getSuperclass() != null ? getField(
//					clazz.getSuperclass(), name) : null;
//		}
//	}
//
//	private static Class<?> getActualCapsuleClass(Class<?> clazz) {
//		while (clazz != null && !clazz.getName().equals(CAPSULE_CLASS_NAME))
//			clazz = clazz.getSuperclass();
//		return clazz;
//	}
//
//	private static Object invoke(Object obj, Method method, Object... params) {
//		try {
//			return method.invoke(obj, params);
//		} catch (Exception e) {
//			throw rethrow(e);
//		}
//	}
//
//	private static <T extends AccessibleObject> T accessible(T x) {
//		if (!x.isAccessible())
//			x.setAccessible(true);
//		return x;
//	}
//
//	private static Object get(Object obj, Field field) {
//		try {
//			return field.get(obj);
//		} catch (Exception e) {
//			throw rethrow(e);
//		}
//	}
//
//	private static void set(Object obj, Field field, Object value) {
//		try {
//			field.set(obj, value);
//		} catch (Exception e) {
//			throw rethrow(e);
//		}
//	}
//	// </editor-fold>
//}